﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text;
using Asset;
using UnityEditor.Build.Reporting;

namespace BuildAseets
{
    public enum Build_Type
    {
        Single,
        Multi,
    }
    public class AssetBundleBuildInfo
    {
        public Build_Type buildType;//单个文件打一个bundle 还是一个文件夹打一个bundle
        public string[] fileSuffs;//*.jpg *.png
        public string folderPath;//例如Assets/Res/AssetBundle/Atlas

        public AssetBundleBuildInfo(Build_Type buildType, string folderPath, string[] fileSuffs)
        {
            this.folderPath = folderPath;
            this.fileSuffs = fileSuffs;
            this.buildType = buildType;
        }
    }

    public class BuildAsset
    {
        //资源路径
        private const string exportABPath = "Assets/StreamingAssets";

        private static List<AssetBundleBuildInfo> getInfo()
        {
            List<AssetBundleBuildInfo> lst = new List<AssetBundleBuildInfo>()
            {
                new AssetBundleBuildInfo( Build_Type.Multi,"Assets/Res/AssetBundle/Atlas",new string[]{ ".jpg",".png"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/Textures",new string[]{ ".jpg",".png"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/SceneTextures",new string[]{ ".jpg",".png",".tga"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/Cfgs",new string[]{ ".asset"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/Shaders",new string[]{ ".shader"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/Materials",new string[]{ ".mat"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/Prefabs",new string[]{ ".prefab",".anim",".psb",".controller"}),
                new AssetBundleBuildInfo( Build_Type.Single,"Assets/Res/AssetBundle/Scenes",new string[]{ ".unity"}),
        };
            return lst;
        }

        //打包ab
        [MenuItem("Assets/打包相关/导出AssetBundle", false, 7001)]
        private static void buildAssetBundle()
        {
            string exportPath = Path.Combine(Application.dataPath, "StreamingAssets");
            checkFullPath(exportPath);
            List<AssetBundleBuildInfo> lst = getInfo();
            List<AssetBundleBuild> buildLst = new List<AssetBundleBuild>();
            for (int i = 0; i < lst.Count; i++)
            {
                buildAssetBundleByInfo(lst[i], buildLst);
            }
            BuildPipeline.BuildAssetBundles(exportABPath, buildLst.ToArray(), BuildAssetBundleOptions.DisableWriteTypeTree, BuildTarget.StandaloneWindows);
            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
            UnityEngine.Debug.LogError("导出AssetBundle完成");
        }

        private static void buildAssetBundleByInfo(AssetBundleBuildInfo info, List<AssetBundleBuild> buildLst)
        {
            string path = info.folderPath;
            string fullPath = getFullPath(path);
            checkFullPath(fullPath);
            if (info.buildType == Build_Type.Multi)
            {
                //每个文件夹打一个ab
                //获取所有文件夹
                List<string> folders = FileUtils.getAllFolder(fullPath, false);
                for (int i = 0; i < folders.Count; i++)
                {
                    string assetBundleName = getAbName(folders[i]);
                    List<string> files = FileUtils.getFiles(folders[i], info.fileSuffs);
                    addBuild(files, buildLst, assetBundleName);
                }
            }
            else
            {
                //如果是单独打ab 获取下面所有文件 打包ab
                List<string> files = FileUtils.getAllFiles(fullPath, info.fileSuffs);
                addBuild(files, buildLst);
            }
        }

        private static void addBuild(List<string> files, List<AssetBundleBuild> buildLst, string assetBundleName = null)
        {
            for (int k = 0; k < files.Count; k++)
            {
                string assetRpath = FileUtil.GetProjectRelativePath(files[k]);
                AssetImporter imp = AssetImporter.GetAtPath(assetRpath);
                if (imp != null)
                {
                    string addressName = Path.GetFileNameWithoutExtension(files[k]).ToLower();
                    string bundleName = string.IsNullOrEmpty(assetBundleName) ? getAbName(files[k]) : assetBundleName;
                    imp.assetBundleName = bundleName;
                    AssetBundleBuild build = new AssetBundleBuild();
                    build.assetBundleName = bundleName;//bundle的名称
                    build.assetNames = new string[] { assetRpath };//资源在工程的路径
                    build.addressableNames = new string[] { addressName };//资源在bundle中的名称
                    //string log = string.Format("资源路径:{0}   BundleName:{1}   AssetName:{2}", assetRpath, bundleName, addressName);
                    //Debug.Log(log);
                    buildLst.Add(build);
                    EditorUtility.SetDirty(imp);
                }
                else
                {
                    Debug.LogWarning("AssetImporter == null  " + assetRpath);
                }
            }
        }

        private const string assetEditorCfgPath = "Res/AssetBundle/Cfgs/EditorAssetMap.asset";
        private const string assetCfgPath = "Res/AssetBundle/Cfgs/AssetMap.asset";
        //编辑器模式配置
        [MenuItem("Assets/打包相关/导出Editor配置", false, 6008)]
        private static void buildEditorCfg()
        {
            string cfgFullPath = getFullPath(assetEditorCfgPath);
            deleteFile(cfgFullPath);
            EditorAssetCfg assetCfg = ScriptableObject.CreateInstance<EditorAssetCfg>();
            List<EditorBuildSettingsScene> editorBuildSettings = new List<EditorBuildSettingsScene>();
            List<AssetBundleBuildInfo> lst = getInfo();
            for (int k = 0; k < lst.Count; k++)
            {
                AssetBundleBuildInfo info = lst[k];
                string path = info.folderPath;
                string fullPath = getFullPath(path);
                checkFullPath(fullPath);
                //编辑器下面 存一个资源名称->路径的隐射 忽略 Build_Type.Multi 混合
                if (info.buildType == Build_Type.Multi)
                {
                    //检查混合文件夹下面  不能有单独的文件  
                    List<string> errorFiles = FileUtils.getFiles(fullPath, info.fileSuffs);
                    if (errorFiles.Count > 0)
                    {
                        for (int i = 0; i < errorFiles.Count; i++)
                        {
                            UnityEngine.Debug.LogError("混合打包文件下面有多余的资源 " + errorFiles[i]);
                        }
                    }
                }
                List<string> files = FileUtils.getAllFiles(fullPath, info.fileSuffs);
                for (int i = 0; i < files.Count; i++)
                {
                    string assetRpath = FileUtil.GetProjectRelativePath(files[i]);
                    string addressName = Path.GetFileNameWithoutExtension(files[i]);
                    assetCfg.assetNames.Add(addressName.ToLower());
                    assetCfg.assetPaths.Add(assetRpath.ToLower());
                    string filesPath = files[i];
                    if (filesPath.EndsWith(".unity"))
                    {
                        EditorBuildSettingsScene editorBuildSettingsScene = new EditorBuildSettingsScene(assetRpath, true);
                        editorBuildSettings.Add(editorBuildSettingsScene);
                    }
                }
            }
            EditorBuildSettings.scenes = editorBuildSettings.ToArray();
            string cfgRpath = FileUtil.GetProjectRelativePath(cfgFullPath); //getRelativePath(cfgFullPath);
            AssetDatabase.CreateAsset(assetCfg, cfgRpath);
            UnityEngine.Debug.LogError("导出Editor配置完成");
        }

        //runtime配置
        [MenuItem("Assets/打包相关/导出Assetbundle配置", false, 6009)]
        private static void buildRunTimeCfg()
        {
            string cfgFullPath = getFullPath(assetCfgPath);
            deleteFile(cfgFullPath);
            AssetCfg assetCfg = ScriptableObject.CreateInstance<AssetCfg>();

            List<AssetBundleBuildInfo> lst = getInfo();
            for (int k = 0; k < lst.Count; k++)
            {
                AssetBundleBuildInfo info = lst[k];
                string path = info.folderPath;
                string fullPath = getFullPath(path);
                checkFullPath(fullPath);
                //Run Time 配置
                if (info.buildType == Build_Type.Multi)
                {
                    List<string> folders = FileUtils.getAllFolder(fullPath, false);
                    for (int i = 0; i < folders.Count; i++)
                    {
                        string assetBundleName = getAbName(folders[i]);
                        List<string> files = FileUtils.getFiles(folders[i], info.fileSuffs);
                        addRunTimeCfg(files, assetCfg, assetBundleName);
                    }
                }
                else
                {
                    List<string> files = FileUtils.getAllFiles(fullPath, info.fileSuffs);
                    addRunTimeCfg(files, assetCfg);
                }
            }
            string cfgRpath = FileUtil.GetProjectRelativePath(cfgFullPath); //getRelativePath(cfgFullPath);
            AssetDatabase.CreateAsset(assetCfg, cfgRpath);
            UnityEngine.Debug.LogError("导出Assetbundle配置完成");
        }

        private static void addRunTimeCfg(List<string> files, AssetCfg assetCfg, string assetBundleName = null)
        {
            for (int k = 0; k < files.Count; k++)
            {
                string bundleName = string.IsNullOrEmpty(assetBundleName) ? getAbName(files[k]) : assetBundleName;
                string addressName = Path.GetFileNameWithoutExtension(files[k]);
                assetCfg.assetNames.Add(addressName.ToLower());
                assetCfg.bundleNames.Add(bundleName.ToLower().Replace(@"\", "/"));
            }
        }

        private static void checkFullPath(string fullPath)
        {
            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(fullPath);
            }
        }

        //获取完整路径
        private static string getFullPath(string suff)
        {
            if (suff.StartsWith("Assets/"))
            {
                suff = suff.Replace("Assets/", "");
            }
            return Path.Combine(Application.dataPath, suff);
        }
        //根据完整路径获取相对路径
        private static string getRelativePath(string full)
        {
            int index = full.IndexOf("Assets");
            string path = full.Substring(index);
            return path;
        }
        //Atlas abName
        public static string getAbName(string path)
        {
            int index = path.IndexOf("AssetBundle");
            string name = path.Substring(index);
            int suffIndex = name.LastIndexOf(".");
            if (suffIndex > 0)
            {
                name = name.Substring(0, suffIndex);
            }
            return name;
        }
        //获取文件名称
        public static string getOtherAbName(string filePath)
        {
            return Path.GetFileNameWithoutExtension(filePath);
        }

        private static void checkPath(string path)
        {
            path = path.Replace("Assets/", "");
            if (!Directory.Exists(Path.Combine(Application.dataPath, path)))
            {
                Directory.CreateDirectory(Path.Combine(Application.dataPath, path));
            }
            AssetDatabase.Refresh();
        }

        private static void deleteFile(string file)
        {
            if (File.Exists(file))
            {
                File.Delete(file);
            }
            AssetDatabase.Refresh();
        }

    }

}